# -*-coding:utf-8-*-

import json
from bson.objectid import ObjectId
from pyrestful import mediatypes
from pyrestful.rest import get, post, put, delete
from utils.auth import authenticated
from handlers.base import BaseHandler
from tornado.gen import coroutine, Return


class DevicesHandler(BaseHandler):
    def __init__(self, application, request, **kwargs):
        super(DevicesHandler, self).__init__(application, request, **kwargs)
        self.delegate_name = 'devices'
        self.wait_id = None

    @coroutine
    def check_device_id(self, device_id):
        result = yield self.devices_dao.is_device_exists(device_id)
        if not result:
            self.respond_error('invalid_device_id')

    @coroutine
    def check_device_owner(self, device_id):
        owner_id = yield self.devices_dao.get_owner_of_device(device_id)
        if owner_id is None or (ObjectId.is_valid(owner_id) and owner_id != self.user_id):
            self.respond_error('not_your_own_device')

    @get(_path='/api/devices')
    @authenticated
    @coroutine
    def get_device_list(self):
        result = yield self.delegate_get_list(self.devices_dao, None)
        self.respond_success(result)

    @post(_path='/api/devices', _types=[dict],
          _consumes=mediatypes.APPLICATION_JSON)
    @authenticated
    @coroutine
    def add_device(self, request):
        device_id = request['device_id']
        yield self.check_device_id(device_id)
        owner_id = yield self.devices_dao.get_owner_of_device(device_id)
        if owner_id is not None and ObjectId.is_valid(owner_id):
            if owner_id == self.user_id:
                self.respond_error('device_already_exists')
            else:
                self.respond_error('device_own_by_other')
        request['owner_id'] = self.user_id
        yield self.devices_dao.update_device(self.user_id, device_id, request)
        self.respond_success({'device_id': device_id})

    @get(_path='/api/devices/{aspect}', _types=[str])
    @authenticated
    @coroutine
    def get_device_aspect(self, aspect):
        if 'count' == aspect:
            result = yield self.delegate_get_list(self.devices_dao, 'device_id', get_count=True)
        else:
            device_id = aspect
            yield self.check_device_id(device_id)
            yield self.check_device_owner(device_id)
            result = yield self.devices_dao.get_device(self.user_id, device_id)
        self.respond_success(result)

    @put(_path='/api/devices/{device_id}', _types=[str],
         _consumes=mediatypes.APPLICATION_JSON)
    @authenticated
    @coroutine
    def update_device(self, device_id, request):
        yield self.check_device_id(device_id)
        yield self.check_device_owner(device_id)
        if 'owner_id' in request:
            del request['owner_id']
        result = yield self.devices_dao.update_device(self.user_id, device_id, request)
        if result and 'power_on' in request:
            topic = 't/d/%s/n/power_on' % device_id
            payload = dict(power_on=request['power_on'])
            payload = json.dumps(payload)
            self.mqtornado.publish(topic, payload)
        self.respond_success(result)

    @delete(_path='/api/devices/{device_id}', _types=[str])
    @authenticated
    @coroutine
    def delete_device(self, device_id):
        yield self.check_device_id(device_id)
        yield self.check_device_owner(device_id)
        result = yield self.devices_dao.delete_device(self.user_id, device_id)
        self.respond_success(result)

    '''
    Internal interfaces
    '''

    @get(_path='/internal/api/devices/{device_id}', _types=[str])
    @coroutine
    def internal_get_device(self, device_id):
        fields = ['enabled', 'power_on']
        result = yield self.devices_dao.internal_get_device(device_id, fields)
        self.respond_success(result)

    @put(_path='/internal/api/devices/{device_id}', _types=[str],
         _consumes=mediatypes.APPLICATION_JSON)
    @coroutine
    def internal_update_device(self, device_id, request):
        result = yield self.devices_dao.internal_update_device(device_id, request)
        self.respond_success(result)

    @put(_path='/internal/api/devices/{device_id}/specifics/{field}', _types=[str, str],
         _consumes=mediatypes.APPLICATION_JSON)
    @coroutine
    def internal_update_device_specifics(self, device_id, field, request):
        result = yield self.devices_dao.internal_update_device_specifics(device_id, field, request)
        self.respond_success(result)

    @get(_path='/internal/api/devices/{device_id}/specifics/{field}', _types=[str, str],
         _produces=mediatypes.APPLICATION_JSON)
    @coroutine
    def internal_get_device_specifics(self, device_id, field):
        yield self._get_device_specifics(device_id, field)

    '''
    Specifics interfaces
    '''

    @get(_path='/api/devices/{device_id}/specifics/{field}', _types=[str, str])
    @authenticated
    @coroutine
    def get_device_specifics(self, device_id, field):
        yield self.check_device_id(device_id)
        yield self.check_device_owner(device_id)
        yield self._get_device_specifics(device_id, field)

    @coroutine
    def _get_device_specifics(self, device_id, field):
        result = yield self.devices_dao.get_device_specifics(device_id, field)
        self.respond_success(result)
